﻿#include "pch.h"
#include "qgp/qgach.h"
#include "qgp/qgadt.h"

//////////////////////////////////////////////////////////////////////////
// 데픽트
KIMPL_SUBCLASS_ABSTRACT(qgDpct, "Depict");

//
qgDpct::qgDpct()
{
	_visible = true;

	// calc -> 단위
	// local -> 단위
	// trfm.loc -> 단위
	// trfm.rot -> 단위
	// trfm.scl -> 비스듬 단위
	_calc._11 = _calc._22 = _calc._33 = _calc._44 = 1.0f;
	_local._11 = _local._22 = _local._33 = _local._44 = 1.0f;
	_trfm.rot.w = 1.0f;
	_trfm.scl.x = _trfm.scl.y = _trfm.scl.z = 1.0f;
}

//
bool qgDpct::Update(float adv)
{
	k_return_value_if_fail(_visible, false);

	UpdateTM();
	UpdateSub(adv);

	return true;
}

//
void qgDpct::Draw()
{

}

//
void qgDpct::SetLocation(const tpl::Vec3& v)
{
	_trfm.loc = v;
	NeedUpdate();
}

//
void qgDpct::SetRotation(const tpl::Quat& q)
{
	_trfm.rot = q;
	NeedUpdate();
}

//
void qgDpct::SetScaling(const tpl::Vec3& v)
{
	_trfm.scl = v;
	NeedUpdate();
}

//
void qgDpct::SetName(const char* name)
{
	k_strncpy(_name, name, 64 - 1);
	_hashcode = k_strihash(_name);
}

//
void qgDpct::SetCalcTM(const tpl::Mat4& tm)
{
	_calc = tm;
	SetUpdated(true);
}

//
void qgDpct::SetLocalTM(const tpl::Mat4 tm)
{
	_local = tm;
	SetUpdated(true);
}

//
bool qgDpct::AddSub(qgDpct* node)
{
	k_return_value_if_fail(node && node != this, false);

	if (node->_link.parent)
	{
		node->Unload();
		node->_link.parent->RemoveSub(node, false);
	}

	if (_link.sub_frst)
		_link.sub_frst->_link.prev = node;
	else
		_link.sub_last = node;
	node->_link.next = _link.sub_frst;
	node->_link.prev = NULL;
	_link.sub_frst = node;
	_link.sub_count++;

	node->_link.parent = this;

	return true;
}

//
bool qgDpct::RemoveSub(qgDpct* node, bool checkall)
{
	k_return_value_if_fail(node->_link.parent == this, false);

	if (checkall)
	{
		qgDpct* fnd = NULL;
		for (qgDpct* tmp = _link.sub_last; tmp; tmp = tmp->_link.prev)
		{
			if (node == tmp)
			{
				fnd = tmp;
				break;
			}
		}

		if (!fnd)
			return false;
	}

	node->_link.parent = NULL;

	if (node->_link.next)
		node->_link.next->_link.prev = node->_link.prev;
	else
		_link.sub_last = node->_link.prev;
	if (node->_link.prev)
		node->_link.prev->_link.next = node->_link.next;
	else
		_link.sub_frst = node->_link.next;
	_link.sub_count--;

	if (node->Unload() > 0)
	{
		node->_link.prev = NULL;
		node->_link.next = NULL;
	}

	return true;
}

//
void qgDpct::ClearSub()
{
	qgDpct* next;
	for (qgDpct* node = _link.sub_frst; node; node = next)
	{
		next = node->_link.next;
		node->_link.parent = NULL;
		if (node->Unload() > 0)
		{
			node->_link.prev = NULL;
			node->_link.next = NULL;
		}
	}

	_link.sub_frst = NULL;
	_link.sub_last = NULL;
	_link.sub_count = 0;
}

//
qgDpct* qgDpct::GetSub(const char* name)
{
	k_return_value_if_fail(name != NULL, NULL);

	ksize_t hash = k_strihash(name);
	for (qgDpct* tmp = _link.sub_last; tmp; tmp = tmp->_link.prev)
	{
		if (tmp->_hashcode == hash && tmp->_name == name)
			return tmp;
	}

	return NULL;
}

//
qgDpct* qgDpct::FindSub(kint id)
{
	for (qgDpct* tmp = _link.sub_last; tmp; tmp = tmp->_link.prev)
	{
		if (tmp->_id == id)
			return tmp;
	}

	return NULL;
}

//
bool qgDpct::UpdateTM()
{
	bool ret;

	if (_updated)
		ret = true;
	else
	{
		ret = false;
		SetUpdated(true);

		_local = tpl::Mat4::Transform(_trfm);
	}

	if (_link.parent)
		_calc = _local * _link.parent->_calc;
	else
		_calc = _local;

	return ret;
}

//
void qgDpct::UpdateSub(float adv)
{
	for (qgDpct* node = _link.sub_frst; node; node = node->_link.next)
		node->Update(adv);
}



